package com.joelemon.mockinfluxdbdata.mock.wokers;

import cn.hutool.core.date.DateTime;
import com.joelemon.mockinfluxdbdata.common.SystemException;
import com.joelemon.mockinfluxdbdata.core.config.MockTask;
import com.joelemon.mockinfluxdbdata.core.config.MockTaskService;
import com.joelemon.mockinfluxdbdata.core.log.MockTaskLogService;
import com.joelemon.mockinfluxdbdata.enums.CommonFlag;
import com.joelemon.mockinfluxdbdata.enums.RunningFlag;
import com.joelemon.mockinfluxdbdata.mock.ConnectConfig;
import com.joelemon.mockinfluxdbdata.mock.DataLine;
import com.joelemon.mockinfluxdbdata.mock.MockConfig;
import com.joelemon.mockinfluxdbdata.mock.VisableInfo;
import com.joelemon.mockinfluxdbdata.mock.service.DefaultDBInsertService;
import com.joelemon.mockinfluxdbdata.mock.service.DelayedQueueConsumer;
import com.joelemon.mockinfluxdbdata.mock.service.MockHandleService;
import com.joelemon.mockinfluxdbdata.mock.service.MockHandleServiceFactory;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Description: 服务实现V1
 * @Author: HJY
 * @Date: 2023/11/20
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class DBInsertWokerV2 implements DBInsertWokerService {

    private final MockTaskService mockTaskService;
    private final DefaultDBInsertService defaultDBInsertService;
    private final MockTaskLogService mockTaskLogService;
    private final MockHandleServiceFactory mockHandleServiceFactory;

    private DelayedQueueConsumer delayedQueueConsumer;

    @PostConstruct
    public void initDelay() {
        delayedQueueConsumer = new DelayedQueueConsumer(this);
        // 创建一个线程消费
        new Thread(delayedQueueConsumer).start();
    }


//    @Scheduled(cron = "0/1 * * * * ?")
    @Override
    public void syncJob() {
        List<MockTask> prepareTasks = mockTaskService.prepareNewTasks();
        if (prepareTasks != null) {
            prepareTasks.forEach(task -> {
                VisableInfo visableInfo = new VisableInfo();
                visableInfo.setTaskId(task.getId());
                task.setVisableInfo(visableInfo);
                handleWork(task);
            });
        }
    }

    @Async
    public void handleWork(MockTask task) {
        MockConfig mockConfig = task.parseConfig();
        ConnectConfig connectConfig = task.parseConnectConfig();
        VisableInfo visableInfo = task.getVisableInfo();
        try {
            if (task.check()) {
                MockHandleService mockHandleService = mockHandleServiceFactory.getMockHandleService(task.getConfigType());
                if (mockHandleService == null) {
                    throw new SystemException("没有该类型的服务实现");
                }

                if (visableInfo.getBeginTime() == null)
                    visableInfo.setBeginTime(mockConfig.getInsertStrategy().getStart());
                if (visableInfo.getStartTime() == null)
                    visableInfo.setStartTime(new DateTime());
                // 校验是否需要强制停止
                MockTask checkMockTaskData = mockTaskService.getTask(visableInfo.getTaskId());
                if (checkMockTaskData == null || CommonFlag.YES.equals(checkMockTaskData.getForceStop())) {
                    // 强制停止
                    visableInfo.setStopTime(new DateTime());
                    visableInfo.setForceStop(true);
                    mockTaskLogService.log(visableInfo, null);
                    if (checkMockTaskData != null) {
                        mockTaskService.updateStatus(visableInfo.getTaskId(), RunningFlag.COMPLETED);
                    }
                    return;
                }
                while (true) {
                    // 生成模拟数据
                    List<DataLine> mockDatas = mockHandleService.mock(mockConfig);
                    if (mockDatas != null && mockDatas.size() > 0) {
                        int result = defaultDBInsertService.insert(connectConfig, mockDatas, mockConfig.getInsertType());
                        if (result > 0) {
                            AtomicInteger insertNum = visableInfo.getInsertNum();
                            insertNum.addAndGet(mockDatas.size());
                        }
                        visableInfo.setArriveTime(new DateTime());
                    } else {
                        break;
                    }
                }
                // 需要延迟继续处理
                Long delaySecs = mockHandleService.needDalaySeconds(mockConfig);
                if (delaySecs != null && delaySecs > 0) {
                    delayTask(delaySecs, task);
                } else {
                    mockTaskLogService.log(visableInfo, null);
                    mockTaskService.updateStatus(visableInfo.getTaskId(), RunningFlag.COMPLETED);
                }
            }
        } catch (Exception e) {
            mockTaskLogService.log(visableInfo, e.getMessage());
            mockTaskService.updateStatus(visableInfo.getTaskId(), RunningFlag.FAILED);
            log.error("系统异常 {}", e);
        }
    }

    @Override
    public void clear() {
        // 获取所有的延迟队列任务
        MockTask[] mockTasks = delayedQueueConsumer.clearQueue();
        // 刷新状态并记录结果
        if (mockTasks != null) {
            for (MockTask mockTask : mockTasks) {
                // 更新任务状态
                mockTaskService.updateStatus(mockTask.getId(), RunningFlag.COMPLETED);
                // 记录日志
                mockTaskLogService.log(mockTask.getVisableInfo(), "强制停止，任务被取消：" + new DateTime());
            }
        }
    }

    // 延迟队列处理
    public void delayTask(Long delaySecond, MockTask task) {
        // 设置下次触发的时间
        long delayTime = System.currentTimeMillis() + delaySecond * 1000L;
        task.getMockConfig().getInsertStrategy().setNextRunningTime(delayTime);
        // 放入延时队列中
        log.debug(System.currentTimeMillis() + "===>延迟开始：" + delayTime + task);
        delayedQueueConsumer.putDelayJob(task);
    }
}
